package com.xj.algorithm.leetcode;

import java.util.*;

/**
 * 二叉树的坡度
 */
public class L563_二叉树的坡度 {

    /**
     * 给定一个二叉树，计算整个树的坡度。
     * <p>
     * 一个树的节点的坡度定义即为，该节点左子树的结点之和和右子树结点之和的差的绝对值。空结点的的坡度是0。
     * <p>
     * 整个树的坡度就是其所有节点的坡度之和。
     * <p>
     * 示例:
     * <p>
     * 输入:
     * 1
     * /   \
     * 2     3
     * 输出: 1
     * 解释:
     * 结点的坡度 2 : 0
     * 结点的坡度 3 : 0
     * 结点的坡度 1 : |2-3| = 1
     * 树的坡度 : 0 + 0 + 1 = 1
     * 注意:
     * <p>
     * 任何子树的结点的和不会超过32位整数的范围。
     * 坡度的值不会超过32位整数的范围。
     */
    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        System.out.println(findTilt(root));

        System.out.println(findTiltOffice(root));
    }

    //自己的解法：后序遍历+递归。这是一个循环。可能会超时
    static int totalTilt = 0;
    public static int findTilt(TreeNode root) {
        totalTilt=0;
        if (root == null) {
            return 0;
        }

        //每个节点都要计算坡度
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            List<Integer> leftList = new ArrayList<>();
            findNodeSum(node.left, leftList);
            int leftSum = 0;
            for (int v : leftList) {
                leftSum += v;
            }

            List<Integer> rightList = new ArrayList<>();
            findNodeSum(node.right, rightList);
            int rightSum = 0;
            for (int v : rightList) {
                rightSum += v;
            }

            int tilt = Math.abs(leftSum - rightSum);
            totalTilt = totalTilt + tilt;

            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        return totalTilt;
    }

    //查找树的节点和
    public static void findNodeSum(TreeNode root, List<Integer> values) {
        if (root == null) {
            return;
        }
        findNodeSum(root.left, values);
        findNodeSum(root.right, values);
        values.add(root.val);
    }


    //官方解法：创建一个当前树的求和的递归,在求和过程中，全局变量进行坡度计算并累加
    public static int findTiltOffice(TreeNode root) {
        traverse(root);
        return tilt;
    }

    static int tilt=0;
    public static int traverse(TreeNode root) {
        if(root==null ) {
            return 0;
        }
        int left=traverse(root.left);
        int right=traverse(root.right);
        tilt+=Math.abs(left-right);
        return left+right+root.val;
    }

}
